#include <iostream>
#include <string>
#include <unistd.h>
#include <mutex>
#include "mutex.hpp"

using namespace MutexModule;

#if 0
// c++11 <mutex>
/* 抢票系统 */
int ticket = 1000; /* 票数 */
std::mutex lock;
void *routine(void *args)
{
    std::string name = static_cast<const char*>(args);
    while(true)
    {
        /* 加锁 */
        lock.lock();
        if(ticket > 0)
        {
            usleep(1000);
            std::cout << name << " Get a ticket, having: " << ticket << " leave" << std::endl;
            lock.unlock();
            ticket--;
        }
        else
        {
            lock.unlock();
            break;
        }
    }
    return nullptr;
}

int main()
{
    pthread_t t[4];
    pthread_create(&t[1], nullptr, routine, (void*)"thread-1");
    pthread_create(&t[2], nullptr, routine, (void*)"thread-2");
    pthread_create(&t[3], nullptr, routine, (void*)"thread-3");
    pthread_create(&t[4], nullptr, routine, (void*)"thread-4");

    pthread_join(t[1], nullptr);
    pthread_join(t[2], nullptr);
    pthread_join(t[3], nullptr);
    pthread_join(t[4], nullptr);

    return 0;
}
#endif

#if 0
// V3
class ThreadData
{
public:
    ThreadData(const std::string &name, Mutex &lock)
        : _name(name), _lockp(&lock)
    {
    }

    Mutex *GetMutex()
    {
        return _lockp;
    }

    const std::string &name()
    {
        return _name;
    }

    ~ThreadData()
    {
    }

private:
    std::string _name;
    Mutex *_lockp;
};

/* 抢票系统 */
int ticket = 1000; /* 票数 */
Mutex lock;
void *routine(void *args)
{
    ThreadData* td = static_cast<ThreadData*>(args);
    while(true)
    {
        /* 加锁 */
        LockGuard guard(*td->GetMutex());
        if(ticket > 0)
        {
            usleep(1000);
            std::cout << td->name() << " Get a ticket, having: " << ticket << " leave" << std::endl;
            ticket--;
        }
        else
        {
            break;
        }
    }
    return nullptr;
}

int main()
{
    pthread_t t[4];
    Mutex lock;

    ThreadData* td1 = new ThreadData("thread-1", lock);
    pthread_create(&t[1], nullptr, routine, (void*)td1);

    ThreadData* td2 = new ThreadData("thread-2", lock);
    pthread_create(&t[2], nullptr, routine, (void*)td2);

    ThreadData* td3 = new ThreadData("thread-3", lock);
    pthread_create(&t[3], nullptr, routine, (void*)td3);

    ThreadData* td4 = new ThreadData("thread-4", lock);
    pthread_create(&t[4], nullptr, routine, (void*)td4);

    pthread_join(t[1], nullptr);
    pthread_join(t[2], nullptr);
    pthread_join(t[3], nullptr);
    pthread_join(t[4], nullptr);

    return 0;
}
#endif


#if 0
// V2
/* 抢票系统 */
int ticket = 1000; /* 票数 */
Mutex lock;
void *routine(void *args)
{
    std::string name = static_cast<const char*>(args);
    while(true)
    {
        /* 加锁 */
        LockGuard guard(lock);
        if(ticket > 0)
        {
            usleep(1000);
            std::cout << name << " Get a ticket, having: " << ticket << " leave" << std::endl;
            ticket--;
        }
        else
        {
            break;
        }
    }
    return nullptr;
}

int main()
{
    pthread_t t[4];
    pthread_create(&t[1], nullptr, routine, (void*)"thread-1");
    pthread_create(&t[2], nullptr, routine, (void*)"thread-2");
    pthread_create(&t[3], nullptr, routine, (void*)"thread-3");
    pthread_create(&t[4], nullptr, routine, (void*)"thread-4");

    pthread_join(t[1], nullptr);
    pthread_join(t[2], nullptr);
    pthread_join(t[3], nullptr);
    pthread_join(t[4], nullptr);

    return 0;
}
#endif

#if 0
// V1
/* 抢票系统 */
int ticket = 1000; /* 票数 */
Mutex lock;
void *routine(void *args)
{
    std::string name = static_cast<const char*>(args);
    while(true)
    {
        /* 加锁 */
        lock.Lock();
        if(ticket > 0)
        {
            usleep(1000);
            std::cout << name << " Get a ticket, having: " << ticket << " leave" << std::endl;
            ticket--;
            lock.Unlock();
        }
        else
        {
            lock.Unlock();
            break;
        }
    }
    return nullptr;
}

int main()
{
    pthread_t t[4];
    pthread_create(&t[1], nullptr, routine, (void*)"thread-1");
    pthread_create(&t[2], nullptr, routine, (void*)"thread-2");
    pthread_create(&t[3], nullptr, routine, (void*)"thread-3");
    pthread_create(&t[4], nullptr, routine, (void*)"thread-4");

    pthread_join(t[1], nullptr);
    pthread_join(t[2], nullptr);
    pthread_join(t[3], nullptr);
    pthread_join(t[4], nullptr);

    return 0;
}
#endif